﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace POS {
    public partial class MainForm : Form {
        private List<Button> m_bicycleButtons;
        private string CurrentUserName { get; set; }
        private List<BicycleController> BicycleControllersStatus { get; set; }
        private SerialPort m_comport;
        public bool IsSettup { get; set; }
        private bool IsLogin { get; set; }
        private Thread m_readingThread;
        private bool IsClosing = false;
        private object locker = new object();
        public MainForm() {
            InitializeComponent();
            var port = ConfigurationManager.AppSettings["SelectedPortName"];
            m_comport = new SerialPort(port);
            m_comport.StopBits = (StopBits)(Enum.Parse(typeof(StopBits), ConfigurationManager.AppSettings["StopBits"]));

            //m_comport.NewLine = "\n";
            m_comport.Encoding = Encoding.ASCII;
            m_comport.BaudRate = 9600;
            m_comport.DataBits = 8;
            m_comport.Parity = (Parity)Enum.Parse(typeof(Parity), ConfigurationManager.AppSettings["Parity"]);
            m_comport.ReadBufferSize = 16;
            m_comport.NewLine = "\r\n";
            m_comport.Handshake = Handshake.None;
            m_comport.ReceivedBytesThreshold = 17;

            m_bicycleButtons = new List<Button> {
                m_btnNo1,
                m_btnNo2,
                m_btnNo3,
                m_btnNo4,
                m_btnNo5,
                m_btnNo6,
                m_btnNo7,
                m_btnNo8,
                m_btnNo9,
                m_btnNo10,
                m_btnNo11,
                m_btnNo12,
                m_btnNo13,
                m_btnNo14,
                m_btnNo15,
                m_btnNo16,
                m_btnNo17,
                m_btnNo18,
                m_btnNo19,
                m_btnNo20,
            };

            BicycleControllersStatus = new List<BicycleController> {
                new BicycleController{ControllerId = 1,BicycleId = 0,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 2,BicycleId = 1,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 3,BicycleId = 2,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 4,BicycleId = 3,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 5,BicycleId = 4,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 6,BicycleId = 5,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 7,BicycleId = 6,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 8,BicycleId = 7,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 9,BicycleId = 8,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 10,BicycleId = 9,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 11,BicycleId = 10,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 12,BicycleId = 11,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 13,BicycleId = 12,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 14,BicycleId = 13,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 15,BicycleId = 14,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 16,BicycleId = 15,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 17,BicycleId = 16,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 18,BicycleId = 17,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 19,BicycleId = 18,Status = BicycleStatus.Availble, Time = DateTime.Now},
                new BicycleController{ControllerId = 20,BicycleId = 19,Status = BicycleStatus.Availble, Time = DateTime.Now},
            };
            //map tag id to button
            for (int i = 0; i < m_bicycleButtons.Count; i++) {
                m_bicycleButtons[i].Tag = BicycleControllersStatus[i].ControllerId;
            }
            m_comport.Open();
            //m_comport.DataReceived += m_comport_DataReceived;
            m_readingThread = new Thread(OnReceiveBicycle);
            m_readingThread.Start();
        }


        private int ByteToInt(byte[] data) {

            int startIndex = 0;
            int value = data[startIndex];

            for (int i = 1; i < 4; i++) {
                value <<= 8;
                value |= data[i + startIndex];
            }
            return value;
        }
        private long ByteToLong(byte[] data) {
            int startIndex = 0;
            int value = data[startIndex];

            for (int i = 1; i < 8; i++) {
                value <<= 8;
                value |= data[i + startIndex];
            }
            return value;
        }
        private void Copy(byte[] source, byte[] destination, int startIndex, int length) {
            for (int i = 0; i < length; i++) {
                destination[i] = source[startIndex + i];
            }
        }
        private void OnReceiveBicycle() {
            while (!IsClosing) {
                lock (locker) {
                    int count = m_comport.BytesToRead;
                    if (count > 0) {
                        byte[] sizeBuff = new byte[count];
                        try {
                            //var item = m_comport.ReadLine();

                            int rCnt = m_comport.Read(sizeBuff, 0, count);
                            if (rCnt > 0 && rCnt > 3) {
                                byte[] bycicleData = new byte[count - 5];
                                int controllerId =0;
                                for (int i = 0; i < count; i++) {
                                    if (sizeBuff[i] == 0x7f && i>=1) {
                                        controllerId = sizeBuff[i - 1];
                                        break;
                                    }
                                }
                                
                                Copy(sizeBuff, bycicleData, 2, count - 5);


                                var bycicleStr = string.Join("", Encoding.ASCII.GetChars(bycicleData));
                                
                                //var item = serverData[0];
                                //bool lockStatus = BitConverter.ToBoolean(sizeBuff, 16);
                                var tag = bycicleStr.Substring(bycicleStr.LastIndexOf(":") + 1).Trim();
                                int id = 0;
                                var lockStatus =false;
                                if (tag.ToLower().Contains("success")) {
                                    lockStatus = false;
                                } else {
                                    var tagNo = new StringBuilder();
                                    foreach (var c in tag) {
                                        if ("0123456789".IndexOf(c) > 0) {
                                            tagNo.Append(c);
                                        }
                                    }
                                    id = int.Parse(tagNo.ToString());
                                    lockStatus = true;
                                }

                                UpdateBicycleStatus(controllerId, id, DateTime.Now, lockStatus);
                            }
                        } catch (Exception ex) {
                            //TODO: Log 
                        }
                    } 
                }
                

                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
        }
        private void ShowLogin(bool enable) {
            m_pnLogin.Visible = enable;
            m_pnBicycle.Visible = !enable;
            m_pnLogin.Dock = enable ? DockStyle.Fill : DockStyle.None;
            m_pnBicycle.Dock = enable ? DockStyle.None : DockStyle.Fill;
        }

        private void MainForm_Load(object sender, EventArgs e) {
            ShowLogin(true);
            LoadBicycleStatus();
        }

        private void m_btnLogin_Click(object sender, EventArgs e) {
            //TODO: using unformation from database
            if (!IsLogin) {
                if (m_txtUsername.Text == "admin" && m_txtPassword.Text == "admin") {
                    CurrentUserName = m_txtUsername.Text;
                    m_lblWelcome.Text = "Welcome : " + m_txtUsername.Text;
                    m_txtUsername.Text = "";
                    m_txtPassword.Text = "";
                    ShowLogin(false);
                    IsLogin = true;
                }
            } else {

            }


        }

        private void Logout() {
            IsLogin = false;
        }
        private void m_btnCancel_Click(object sender, EventArgs e) {
            m_txtUsername.Text = string.Empty;
            m_txtPassword.Text = string.Empty;
        }

        private void button21_Click(object sender, EventArgs e) {
            SendSelectedData();

            //TODO: Logout 
        }
        private void SendSelectedData() {
            foreach (var bicycleController in BicycleControllersStatus.Where(x => x.Status == BicycleStatus.Choosing).ToList()) {
                SendSelectItem(bicycleController.ControllerId, bicycleController.BicycleId.Value);
            }
        }

        private void CheckSendSelectedItemStatusThread(List<Tuple<int, int>> controllers) {
            int count = 0;
            while (count > 2) {

                count++;

            }
        }
        private void UpdateBicycleStatus(int controllerId, int bicycleId, DateTime time, bool lockStatus) {
            var controller = BicycleControllersStatus.FirstOrDefault(x => x.ControllerId == controllerId);
            if (controller != null) {
                if (lockStatus) {
                    controller.BicycleId = bicycleId;
                } else {
                    controller.BicycleId = null;
                }
                controller.Status = lockStatus ? BicycleStatus.Availble : BicycleStatus.Empty;
                controller.Time = time;
                SetStatusForBicycle(controller.ControllerId, controller.Status);
                //TODO: Update into database
            }
        }

        private void LoadBicycleStatus() {
            foreach (var item in BicycleControllersStatus) {
                SetStatusForBicycle(item.ControllerId, item.Status);
            }
        }

        private void SetStatusForBicycle(int controllerId, BicycleStatus status) {
            this.BeginInvoke((Action)delegate() {
                var item = BicycleControllersStatus.FirstOrDefault(x => x.ControllerId == controllerId);
                var index = BicycleControllersStatus.IndexOf(item);
                m_bicycleButtons[index].Enabled = status == BicycleStatus.Availble;

                if (item != null) {
                    item.Status = status;
                }
                m_bicycleButtons[index].BackColor =
                    status == BicycleStatus.Choosing
                        ? Color.Red
                        : (status == BicycleStatus.Availble ? Color.Green : Color.DarkGray);
            });


        }

        private void OnSelectBicycle(object sender, EventArgs e) {
            Button button = sender as Button;
            if (button != null) {
                if (IsSettup) {
                    var form = new SetupController();
                    if (form.ShowDialog() == DialogResult.OK) {
                        button.Tag = form.ControllerId;
                        var index = m_bicycleButtons.IndexOf(button);
                        BicycleControllersStatus[index].ControllerId = form.ControllerId;
                    }
                } else {
                    int controllerId = (int)button.Tag;
                    SetStatusForBicycle(controllerId, BicycleStatus.Choosing);
                }

            }
        }

        private void SendSelectItem(int controllerId, int bikeId) {
            try {
                //write line to serial port
                //017f 0111 0005 0061 0061 0051 0051 0000 6B
                lock (locker) {
                    var parity = m_comport.Parity;
                    m_comport.Parity = Parity.None;
                    //write line to serial port
                    //017f 0111 0005 0061 0061 0051 0051 0000 6B
                    byte[] data = new byte[18];
                    //long now = DateTime.Now.Ticks;
                    Int16 id = Convert.ToInt16(controllerId);
                    data[0] = (byte)0x01;
                    data[1] = (byte)0x7f;

                    data[2] = (byte)0x01;
                    data[3] = (byte)id;

                    // 0005
                    data[4] = (byte)0x0;
                    data[5] = (byte)0x5;

                    //0061 0061 0051 0051 0000 6B
                    data[6] = (byte)0x00;
                    data[7] = (byte)0x61;

                    data[8] = (byte)0x00;
                    data[9] = (byte)0x61;

                    data[10] = (byte)0x00;
                    data[11] = (byte)0x51;

                    data[12] = (byte)0x00;
                    data[13] = (byte)0x51;

                    data[14] = (byte)0x00;
                    data[15] = (byte)0x00;

                    byte firstXor = data[0];
                    for (int i = 1; i < 16; i++) {
                        firstXor = (byte)(firstXor ^ data[i]);
                    }
                    data[16] = firstXor;
                    //data[17] = secondXor;
                    m_comport.Write(data, 0, 17);
                    m_comport.Parity = parity;

                }

            } catch (System.Exception ex) {
                //baudRatelLabel.Text = ex.Message;
            }
        }

        private void button1_Click(object sender, EventArgs e) {
            IsSettup = !IsSettup;
            if (IsSettup) {
                button1.Text = "Finish Settup";
            } else {
                button1.Text = "Setup Controller";
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
            try {
                IsClosing = true;
                m_comport.Close();
                m_readingThread.Join();
            } catch (Exception ex) {

            }
        }
    }

}
